﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BootyBay.Models;
using System.Linq.Expressions;
using System.Data.Entity;
using System.Reflection;

namespace BootyBay.Repository
{
    public class RepositoryBase<T> : IRepository<T> where T : class
    {
        public BootyBayDBContext DbContext { get; private set; }

        public RepositoryBase()
        {
            DbContext = new BootyBayDBContext();
        }

        public RepositoryBase(BootyBayDBContext dbContext)
        {
            this.DbContext = dbContext;
        }

        protected IDbSet<T> DbSet
        {
            get
            {
                return DbContext.Set<T>();
            }
        }

        public IQueryable<T> GetAll()
        {
            if (typeof(T).GetProperty("IsValid") != null)
            {
                var parameter = Expression.Parameter(typeof(T), "entity");
                var expression = Expression.Lambda<Func<T, bool>>
                    (
                        Expression.Equal(Expression.Property(parameter, "IsValid"), Expression.Constant(true)), parameter
                    );

                return DbSet.Where(expression).AsQueryable();
            }

            return DbSet.AsQueryable();
        }

        public IQueryable<T> SqlQuery(string sql, params object[] parameters)
        {
            var result = DbContext.Database.SqlQuery<T>(sql, parameters);

            return result.AsQueryable();
        }

        public virtual T GetByID(int id)
        {
            if (typeof(T).GetProperty("Id") != null)
            {
                var parameter = Expression.Parameter(typeof(T), "entity");

                var expression = Expression.Lambda<Func<T, bool>>
                    (
                     Expression.Equal(Expression.Property(parameter, "Id"), Expression.Constant(id)), parameter
                    );

                T entity = DbSet.SingleOrDefault(expression);
                return entity;
            }

            return null;
        }

        public virtual T Insert(T entity)
        {
            DbSet.Add(entity);
            DbContext.SaveChanges();

            return entity;
        }

        public virtual T Update(T entity)
        {
            try
            {
                PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);

                var proprityInfo = properties.Where(p => p.Name == "Id").SingleOrDefault();

                var old = GetByID((int)proprityInfo.GetValue(entity, null));

                foreach (var p in properties)
                {
                    p.SetValue(old, p.GetValue(entity, null), null);
                }

                DbContext.SaveChanges();

                return old;
            }
            catch (Exception e)
            {
                return null;
            }
        }

        public virtual void Delete(T entity)
        {
            DbSet.Remove(entity);
            DbContext.SaveChanges();
        }
    }
}
